package com.sbj.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.zhxu.bs.BeanSearcher;
import cn.zhxu.bs.SearchResult;
import cn.zhxu.bs.operator.Contain;
import cn.zhxu.bs.util.MapUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sbj.dto.properties.InviterCodeProperties;
import com.sbj.dto.req.*;
import com.sbj.dto.res.*;
import com.sbj.dto.utils.LocalDateTimeUtils;
import com.sbj.dto.utils.Search;
import com.sbj.entity.Member;
import com.sbj.mapper.MemberMapper;
import com.sbj.service.IMemberService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sbj.service.OrderTimeService;
import com.zmh.framework.constants.Constants;
import com.zmh.framework.enums.ImageTypeEnum;
import com.zmh.framework.enums.ResultCodeEnum;
import com.zmh.framework.exception.ResultException;
import com.zmh.framework.oss.OssConfigure;
import com.zmh.framework.redis.RedisCache;
import com.zmh.framework.util.Base64ToMultipartFile;
import com.zmh.framework.util.MD5;
import com.zmh.framework.util.QrCode;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author summer
 * @since 2024/08/10 10:02:41
 */
@Service
@Transactional(rollbackFor = Exception.class)
@AllArgsConstructor
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> implements IMemberService {

    private final BeanSearcher beanSearcher;

    @Override
    public Page<MemberRes> lists(MemberReq memberReq) {
        Map<String, Object> build = MapUtils.builder().page(memberReq.getPageNum() - 1, memberReq.getPageSize())
                .field(MemberRes::getNickName, memberReq.getNickName()).op(Contain.class)
                .field(MemberRes::getPhone, memberReq.getPhone()).op(Contain.class).build();
        SearchResult<MemberRes> search = beanSearcher.search(MemberRes.class, build);
        return Search.searchDataList(memberReq.getPageNum(), memberReq.getPageSize(), search);
    }

    @Override
    public MemberRes login(WebLoginReq req) {
        LambdaQueryWrapper<Member> eq = Wrappers.lambdaQuery(Member.class).eq(Member::getPhone, req.getPhone());
        Member member = this.getOne(eq);
        if(ObjectUtil.isEmpty(member) || !MD5.aesEncrypt(member.getPhone(),req.getPassword()).equals(member.getPassword())){
            throw new ResultException(ResultCodeEnum.ERROR_USER_NAME_PASS.msg());
        }
        return Convert.convert(MemberRes.class, member);
    }

    @Override
    public void register(RegisterReq req) {
        //verificationCode(req.getPhone(), req.getCode());
        LambdaQueryWrapper<Member> eq = Wrappers.lambdaQuery(Member.class).eq(Member::getPhone, req.getPhone());
        Member member = this.getOne(eq);
        if(ObjectUtil.isNotEmpty(member)){
            throw new ResultException("账号已存在，请重新输入手机号码");
        }
        LambdaQueryWrapper<Member> inviter = Wrappers.lambdaQuery(Member.class).eq(Member::getInviterCode, req.getInviter());
        Member inviterMember = this.getOne(inviter);
        if(ObjectUtil.isEmpty(inviterMember)){
            throw new ResultException("邀请码输入错误,请重新输入");
        }
        Member one = new Member();
        one.setPassword(MD5.aesEncrypt(req.getPhone(), req.getPassword()));
        one.setPhone(req.getPhone());
        one.setInviterCode(RandomUtil.randomString(6));
        one.setInviter(req.getInviter());
        one.setSign(req.getSign());
        this.save(one);
    }

    private  final RedisCache redisCache;;

    private void verificationCode(String phone, String code){
        String phoneCache = redisCache.get(Constants.SMS_ + phone);
        if(StrUtil.isEmpty(phoneCache)){
            throw new ResultException("验证码已过期,请重新获取");
        }
        if(!phoneCache.equals(code)){
            throw new ResultException("验证码输入错误,请重新输入");
        }
    }

    @Override
    public void editPassword(MemberPassReq req) {
        verificationCode(req.getPhone(),req.getCode());
        if(!req.getNewPassWord().equals(req.getConfirmPassWord())){
            throw new ResultException("两次密码输入不一致，请重新输入");
        }
        Member member=this.getById(StpUtil.getLoginIdAsInt());
        if(ObjectUtil.isNotEmpty(member)  && !member.getPhone().equals(req.getPhone()) ){
            throw new ResultException("手机号码不存在,请联系管理员");
        }
        member.setPassword(req.getPhone());
        member.setPassword(MD5.aesEncrypt(req.getPhone(),req.getConfirmPassWord()));
        this.updateById(member);
    }

    private final OssConfigure ossConfigure;

    @Override
    public String uploadAvatar(MultipartFile file) {
        if(file.isEmpty() && StrUtil.isEmpty(file.getOriginalFilename() )) {
            throw new ResultException("请上传头像图片");
        }
        String avatarImage =ossConfigure.getAccessUrl()+ossConfigure.uploadFile(file);
        Member member = new Member();
        member.setId(StpUtil.getLoginIdAsInt());
        member.setAvatarImage(avatarImage);
        this.updateById(member);
        return avatarImage;
    }

    @Override
    public void editNickName(MemberReq memberReq) {
        Member member = new Member();
        member.setId(StpUtil.getLoginIdAsInt());
        member.setNickName(memberReq.getNickName());
        this.updateById(member);
    }

    @Override
    public List<InvitationRes> invitationList() {
        Member member = this.getById(Convert.convert(Integer.class, StpUtil.getLoginId()));
        LambdaQueryWrapper<Member> eq = Wrappers.lambdaQuery(Member.class).eq(Member::getInviter, member.getInviterCode());
        List<Member> list = this.list(eq);
        return Convert.toList(InvitationRes.class,list);
    }

    @Override
    public List<FansRes> fansLists() {
        Member member = this.getById(StpUtil.getLoginIdAsInt());
        Map<String, Object> build = MapUtils.builder().field(FansRes::getInviter, member.getInviterCode()).build();
        SearchResult<FansRes> search = beanSearcher.search(FansRes.class, build);
        return search.getDataList();
    }

    private final InviterCodeProperties codeProperties;

    @Override
    public InviterCodeRes findMemberInviterCode() {
        Member member = this.getById(StpUtil.getLoginIdAsInt());
        String format = StrUtil.format(codeProperties.getCode(), member.getInviterCode());
        InviterCodeRes inviterCodeRes=new InviterCodeRes();
        inviterCodeRes.setInviterCode(member.getInviterCode());
        inviterCodeRes.setBase64(QrCode.sendCode(format,229,229, ImageTypeEnum.PNG));
        return inviterCodeRes;
    }

    @Override
    public MemberRes findMemberInfo() {
        Map<String, Object> build = MapUtils.builder().field(MemberRes::getId, StpUtil.getLoginIdAsInt()).build();
        return beanSearcher.searchFirst(MemberRes.class, build);
    }

    @Override
    public String sign(SignReq signReq) {
        MultipartFile multipartFile = Base64ToMultipartFile.base64ToMultipart(signReq.getBase64());
        return ossConfigure.getAccessUrl()+ ossConfigure.uploadFile(multipartFile);
    }

    @Override
    public void forgetPsd(ForgetPsdReq req) {
        verificationCode(req.getPhone(),req.getCode());
        LambdaQueryWrapper<Member> eq = Wrappers.lambdaQuery(Member.class).eq(Member::getPhone, req.getPhone());
        Member member = this.getOne(eq);
        if(ObjectUtil.isEmpty(member)){
            throw new ResultException("账号不已存在，请重新输入手机号码");
        }
        member.setPassword(MD5.aesEncrypt(req.getPhone(),req.getPassword()));
        this.updateById(member);
    }

    @Override
    public void saveMemberOrderTime(OrderTimeReq orderTimeReq) {
        Member member = this.getById(orderTimeReq.getMemberId());
        member.setStartTime(orderTimeReq.getDateTimeList().get(0));
        member.setEndTime(orderTimeReq.getDateTimeList().get(1));
        this.updateById(member);
    }

    @Override
    public void savePrivilege(MemberReq memberReq) {
        Member member = this.getById(memberReq.getId());
        member.setIsPrivilege(memberReq.getIsPrivilege());
        this.updateById(member);
    }

    private final OrderTimeService orderTimeService;

    @Override
    public OrderTimeRes buyTime() {
        Member member = this.getById(StpUtil.getLoginIdAsInt());
        if(member.getIsPrivilege() && LocalDateTimeUtils.isDateTimeInRange(member.getStartTime(),member.getEndTime(), LocalDateTime.now())){
             OrderTimeRes orderTimeRes=new OrderTimeRes();
             orderTimeRes.setStartTime(LocalTime.parse(member.getStartTime().format(DateTimeFormatter.ofPattern("HH:mm"))));
             orderTimeRes.setEndTime(LocalTime.parse(member.getEndTime().format(DateTimeFormatter.ofPattern("HH:mm"))));
             return orderTimeRes;
        }
        return orderTimeService.buyTime();
    }
}
